home *** CD-ROM | disk | FTP | other *** search
/ Windows Expert / Windows Expert.iso / windownt / uupc11ys.zip / UUCICO / MODEM.C < prev    next >
C/C++ Source or Header  |  1993-04-15  |  33KB  |  887 lines

  1. /*--------------------------------------------------------------------*/
  2. /*    m o d e m . c                                                   */
  3. /*                                                                    */
  4. /*    High level modem control routines for UUPC/extended             */
  5. /*                                                                    */
  6. /*    Copyright (c) 1991 by Andrew H. Derbyshire                      */
  7. /*                                                                    */
  8. /*    Change history:                                                 */
  9. /*       21 Apr 91      Create from dcpsys.c                          */
  10. /*--------------------------------------------------------------------*/
  11.  
  12.  
  13. /*--------------------------------------------------------------------*/
  14. /*                          RCS Information                           */
  15. /*--------------------------------------------------------------------*/
  16.  
  17. /*
  18.  *    $Id: MODEM.C 1.13 1993/04/15 03:21:06 ahd Exp $
  19.  *
  20.  *    Revision history:
  21.  *    $Log: MODEM.C $
  22.  * Revision 1.13  1993/04/15  03:21:06  ahd
  23.  * Add CD() call to hot login procedure
  24.  *
  25.  * Revision 1.12  1993/04/11  00:34:11  ahd
  26.  * Global edits for year, TEXT, etc.
  27.  *
  28.  * Revision 1.11  1993/04/05  04:35:40  ahd
  29.  * Set clear abort processing flag (norecover) from ulib.c
  30.  *
  31.  * Revision 1.10  1993/03/06  23:04:54  ahd
  32.  * make modem connected messages consistent
  33.  *
  34.  * Revision 1.9  1993/01/23  19:08:09  ahd
  35.  * Add additional shutdown() commands even when modem does not init
  36.  *
  37.  * Revision 1.8  1992/12/30  13:11:44  dmwatt
  38.  * Check for NULL brand pointer before comparing
  39.  *
  40.  * Revision 1.7  1992/12/18  12:05:57  ahd
  41.  * Flag variable packet as obsolete
  42.  *
  43.  * Revision 1.6  1992/11/28  19:51:16  ahd
  44.  * Add program exit time to waiting for callin message
  45.  * Make time parameter to callin() const
  46.  *
  47.  * Revision 1.5  1992/11/22  21:20:45  ahd
  48.  * Use strpool for const string allocation
  49.  *
  50.  * Revision 1.4  1992/11/19  03:01:21  ahd
  51.  * drop rcsid
  52.  *
  53.  * Revision 1.3  1992/11/18  03:48:24  ahd
  54.  * Move check of call window to avoid premature lock file overhead
  55.  *
  56.  * Revision 1.2  1992/11/15  20:12:17  ahd
  57.  * Clean up modem file support for different protocols
  58.  *
  59.  * Revision 1.1  1992/11/12  12:32:18  ahd
  60.  * Initial revision
  61.  *
  62.  * Revision 1.1  1992/05/02  13:06:48  ahd
  63.  * Initial revision
  64.  *
  65.  */
  66.  
  67. /*--------------------------------------------------------------------*/
  68. /*                        System include files                        */
  69. /*--------------------------------------------------------------------*/
  70.  
  71. #include <limits.h>
  72. #include <stdio.h>
  73. #include <stdlib.h>
  74. #include <string.h>
  75. #include <ctype.h>
  76. #include <time.h>
  77. #include <limits.h>
  78. #include <sys/types.h>
  79.  
  80. /*--------------------------------------------------------------------*/
  81. /*                    UUPC/extended include files                     */
  82. /*--------------------------------------------------------------------*/
  83.  
  84. #include "lib.h"
  85. #include "arpadate.h"
  86. #include "checktim.h"
  87. #include "dater.h"
  88. #include "dcp.h"
  89. #include "dcpsys.h"
  90. #include "hlib.h"
  91. #include "hostable.h"
  92. #include "modem.h"
  93. #include "script.h"
  94. #include "security.h"
  95. #include "ssleep.h"
  96. #include "catcher.h"
  97. #include "ulib.h"
  98.  
  99. /*--------------------------------------------------------------------*/
  100. /*                          Global variables                          */
  101. /*--------------------------------------------------------------------*/
  102.  
  103. char *device = NULL;          /*Public to show in login banner     */
  104.  
  105. static char **answer, **initialize, **dropline, **ring, **connect;
  106. static char **noconnect;
  107. static char *dialPrefix, *dialSuffix;
  108.  
  109. static INTEGER chardelay, dialTimeout, modemTimeout, scriptTimeout;
  110. static INTEGER answerTimeout, inspeed;
  111. static INTEGER gWindowSize, gPacketSize;
  112. static INTEGER vWindowSize, vPacketSize;
  113. static INTEGER GWindowSize, GPacketSize;
  114.  
  115. INTEGER M_fPacketSize;
  116. INTEGER M_gPacketTimeout;        /* "g" procotol                  */
  117. INTEGER M_fPacketTimeout;        /* "f" procotol                  */
  118. INTEGER M_MaxErr= 10;         /* Allowed errors per single packet    */
  119. INTEGER M_MaxErr;             /* Allowed errors per single packet    */
  120. INTEGER M_xfer_bufsize;       /* Buffering used for file transfers */
  121.  
  122. boolean bmodemflag[MODEM_LAST];
  123.  
  124. static FLAGTABLE modemFlags[] = {
  125.    { "carrierdetect",  MODEM_CD,          B_LOCAL },
  126.    { "direct",         MODEM_DIRECT,      B_LOCAL },
  127.    { "fixedspeed",     MODEM_FIXEDSPEED,  B_LOCAL },
  128.    { "variablepacket", MODEM_VARIABLEPACKET, B_LOCAL | B_OBSOLETE },
  129.    { "largepacket",    MODEM_LARGEPACKET, B_LOCAL | B_OBSOLETE },
  130.    { nil(char) }
  131. }           ;
  132.  
  133. static CONFIGTABLE modemtable[] = {
  134.    { "answer",        (char **) &answer,       B_LIST   | B_UUCICO },
  135.    { "answertimeout", (char **) &answerTimeout,B_INTEGER| B_UUCICO },
  136.    { "biggpacketsize",(char **) &GPacketSize,  B_INTEGER| B_UUCICO },
  137.    { "biggwindowsize",(char **) &GWindowSize,  B_INTEGER| B_UUCICO },
  138.    { "chardelay",     (char **) &chardelay,    B_INTEGER| B_UUCICO },
  139.    { "connect",       (char **) &connect,      B_LIST   | B_UUCICO },
  140.    { "device",        &device,  B_TOKEN  | B_UUCICO | B_REQUIRED },
  141.    { "dialprefix",    &dialPrefix, B_STRING | B_UUCICO | B_REQUIRED },
  142.    { "dialsuffix",    &dialSuffix,             B_STRING | B_UUCICO },
  143.    { "dialtimeout",   (char **) &dialTimeout,  B_INTEGER| B_UUCICO },
  144.    { "fpacketsize",   (char **) &M_fPacketSize,B_INTEGER| B_UUCICO },
  145.    { "fpackettimeout",(char **) &M_fPacketTimeout, B_INTEGER | B_UUCICO },
  146.    { "gpacketsize",   (char **) &gPacketSize,  B_INTEGER| B_UUCICO },
  147.    { "gpackettimeout",(char **) &M_gPacketTimeout, B_INTEGER | B_UUCICO },
  148.    { "gwindowsize",   (char **) &gWindowSize,  B_INTEGER| B_UUCICO },
  149.    { "hangup",        (char **) &dropline,     B_LIST   | B_UUCICO },
  150.    { "initialize",    (char **) &initialize,   B_LIST   | B_UUCICO },
  151.    { "inspeed",       (char **) &inspeed,      B_INTEGER| B_UUCICO },
  152.    { "maximumerrors", (char **) &M_MaxErr,     B_INTEGER| B_UUCICO },
  153.    { "modemtimeout",  (char **) &modemTimeout, B_INTEGER| B_UUCICO },
  154.    { "noconnect",     (char **) &noconnect,    B_LIST   | B_UUCICO },
  155.    { "options",       (char **) bmodemflag,    B_ALL    | B_BOOLEAN},
  156.    { "porttimeout",   NULL,                    B_OBSOLETE },
  157.    { "ring",          (char **) &ring,         B_LIST   | B_UUCICO },
  158.    { "scripttimeout", (char **) &scriptTimeout,B_INTEGER| B_UUCICO },
  159.    { "transferbuffer",(char **) &M_xfer_bufsize, B_INTEGER| B_UUCICO },
  160.    { "vpacketsize",   (char **) &vPacketSize,  B_INTEGER| B_UUCICO },
  161.    { "vwindowsize",   (char **) &vWindowSize,  B_INTEGER| B_UUCICO },
  162.    { nil(char) }
  163. }; /* modemtable */
  164.  
  165. /*--------------------------------------------------------------------*/
  166. /*                    Internal function prototypes                    */
  167. /*--------------------------------------------------------------------*/
  168.  
  169. static boolean getmodem( const char *brand);
  170.  
  171. static boolean dial(char *number, const size_t speed);
  172.  
  173. static boolean sendlist( char **list, int timeout, int lasttimeout,
  174.                          char **failure);
  175.  
  176. static boolean sendalt( char *string, int timeout, char **failure);
  177.  
  178. static void autobaud( const size_t speed);
  179.  
  180. /*--------------------------------------------------------------------*/
  181. /*              Define current file name for references               */
  182. /*--------------------------------------------------------------------*/
  183.  
  184. currentfile();
  185.  
  186. /*--------------------------------------------------------------------*/
  187. /*    c a l l u p                                                     */
  188. /*                                                                    */
  189. /*    script processor - nothing fancy!                               */
  190. /*--------------------------------------------------------------------*/
  191.  
  192. CONN_STATE callup( void )
  193. {
  194.    char *exp;
  195.    int i;
  196.    size_t speed;
  197.  
  198. /*--------------------------------------------------------------------*/
  199. /*             Announce we are trying to call the system              */
  200. /*--------------------------------------------------------------------*/
  201.  
  202.    printmsg(1, "callup: Calling %s via %s at %s on %s",
  203.           rmtname, flds[FLD_TYPE], flds[FLD_SPEED], arpadate());
  204.  
  205.    speed = (size_t) atoi( flds[FLD_SPEED] );
  206.    if (speed < 300)
  207.    {
  208.       printmsg(0,"callup: Modem speed %s is invalid.",
  209.                   flds[FLD_SPEED]);
  210.       hostp->hstatus = invalid_device;
  211.       return CONN_INITIALIZE;
  212.    }
  213.  
  214. /*--------------------------------------------------------------------*/
  215. /*                     Get the modem information                      */
  216. /*--------------------------------------------------------------------*/
  217.  
  218.    if (!getmodem(flds[FLD_TYPE]))
  219.    {
  220.       hostp->hstatus = invalid_device;
  221.       return CONN_INITIALIZE;
  222.    }
  223.  
  224. /*--------------------------------------------------------------------*/
  225. /*                         Dial the telephone                         */
  226. /*--------------------------------------------------------------------*/
  227.  
  228.    if (! dial(flds[FLD_PHONE],speed))
  229.       return CONN_DROPLINE;
  230.  
  231. /*--------------------------------------------------------------------*/
  232. /*             The modem is connected; now login the host             */
  233. /*--------------------------------------------------------------------*/
  234.  
  235.    for (i = FLD_EXPECT; i < kflds; i += 2) {
  236.  
  237.       exp = flds[i];
  238.       printmsg(2, "expecting %d of %d \"%s\"", i, kflds, exp);
  239.       if (!sendalt( exp, scriptTimeout , noconnect))
  240.       {
  241.          printmsg(0, "SCRIPT FAILED");
  242.          hostp->hstatus =  script_failed;
  243.          return CONN_DROPLINE;
  244.       } /* if */
  245.  
  246.       printmsg(2, "callup: sending %d of %d \"%s\"",
  247.                    i + 1, kflds, flds[i + 1]);
  248.       sendstr(flds[i + 1]);
  249.  
  250.    } /*for*/
  251.  
  252.    return CONN_PROTOCOL;
  253.  
  254. } /*callup*/
  255.  
  256. /*--------------------------------------------------------------------*/
  257. /*    c a l l h o t                                                   */
  258. /*                                                                    */
  259. /*    Initialize processing when phone is already off the hook        */
  260. /*--------------------------------------------------------------------*/
  261.  
  262. CONN_STATE callhot( const BPS xspeed )
  263. {
  264.    BPS speed;
  265.  
  266. /*--------------------------------------------------------------------*/
  267. /*                        Open the serial port                        */
  268. /*--------------------------------------------------------------------*/
  269.  
  270.    if (E_inmodem == NULL)
  271.    {
  272.       printmsg(0,"callin: No modem name supplied for incoming calls!");
  273.       panic();
  274.    } /* if */
  275.  
  276.    if (!getmodem(E_inmodem))  /* Initialize modem configuration      */
  277.       panic();                /* Avoid loop if bad modem name        */
  278.  
  279. /*--------------------------------------------------------------------*/
  280. /*                        Set the modem speed                         */
  281. /*--------------------------------------------------------------------*/
  282.  
  283.    if ( xspeed == 0)
  284.       speed = inspeed;
  285.    else
  286.       speed = xspeed;
  287.  
  288. /*--------------------------------------------------------------------*/
  289. /*                    Open the communications port                    */
  290. /*--------------------------------------------------------------------*/
  291.  
  292.    norecovery = FALSE;           // Shutdown gracefully as needed
  293.    if (openline(device, speed, bmodemflag[MODEM_DIRECT] ))
  294.       panic();
  295.  
  296. /*--------------------------------------------------------------------*/
  297. /*                          Initialize stats                          */
  298. /*--------------------------------------------------------------------*/
  299.  
  300.    memset( &remote_stats, 0, sizeof remote_stats);
  301.                               /* Clear remote stats for login        */
  302.    time(&remote_stats.ltime); /* Remember time of last attempt conn  */
  303.    remote_stats.calls ++ ;
  304.  
  305.    if (bmodemflag[MODEM_CD])
  306.       CD();                   /* Set the carrier detect flags        */
  307.  
  308.    return CONN_HOTLOGIN;
  309.  
  310. } /* callhot */
  311.  
  312. /*--------------------------------------------------------------------*/
  313. /*    c a l l i n                                                     */
  314. /*                                                                    */
  315. /*    Answer the modem in passive mode                                */
  316. /*--------------------------------------------------------------------*/
  317.  
  318. CONN_STATE callin( const time_t exit_time )
  319. {
  320.    char c;                    /* A character for input buffer        */
  321.  
  322.    int    offset;             /* Time to wait for telephone          */
  323.    time_t left;
  324.  
  325. /*--------------------------------------------------------------------*/
  326. /*    Determine how long we can wait for the telephone, up to         */
  327. /*    MAX_INT seconds.  Aside from Turbo C limits, this insures we    */
  328. /*    kick the modem once in a while.                                 */
  329. /*--------------------------------------------------------------------*/
  330.  
  331.       left =  exit_time - time(NULL);
  332.       if ( left < 0 )               /* Any time left?                */
  333.          return CONN_EXIT;             /* No --> shutdown            */
  334.  
  335.       if ( left > INT_MAX)
  336.          offset = INT_MAX;
  337.       else
  338.          offset = (int) left;
  339.  
  340. /*--------------------------------------------------------------------*/
  341. /*                        Open the serial port                        */
  342. /*--------------------------------------------------------------------*/
  343.  
  344.    if (E_inmodem == NULL)
  345.    {
  346.       printmsg(0,"callin: No modem name supplied for incoming calls!");
  347.       panic();
  348.    } /* if */
  349.  
  350.    if (!getmodem(E_inmodem))  /* Initialize modem configuration      */
  351.       panic();                /* Avoid loop if bad modem name        */
  352.  
  353.    if ((ring == NULL) || (inspeed == 0))
  354.    {
  355.       printmsg(0,"callin: Missing inspeed and/or ring values in modem \
  356. configuration file.");
  357.       panic();
  358.    } /* if */
  359.  
  360. /*--------------------------------------------------------------------*/
  361. /*                    Open the communications port                    */
  362. /*--------------------------------------------------------------------*/
  363.  
  364.    norecovery = FALSE;           // Shutdown gracefully as needed
  365.    if (openline(device, inspeed, bmodemflag[MODEM_DIRECT]))
  366.       panic();
  367.  
  368. /*--------------------------------------------------------------------*/
  369. /*              Flush the input buffer of any characters              */
  370. /*--------------------------------------------------------------------*/
  371.  
  372.    while (sread(&c ,1,0));    /* Discard trailing trash from modem
  373.                                  connect message                     */
  374.  
  375. /*--------------------------------------------------------------------*/
  376. /*                        Initialize the modem                        */
  377. /*--------------------------------------------------------------------*/
  378.  
  379.    if (!sendlist( initialize, modemTimeout, modemTimeout, NULL))
  380.    {
  381.       printmsg(0,"callin: Modem failed to initialize");
  382.       shutdown();
  383.       panic();
  384.    }
  385.  
  386. /*--------------------------------------------------------------------*/
  387. /*                   Wait for the telephone to ring                   */
  388. /*--------------------------------------------------------------------*/
  389.  
  390.    printmsg(1,"callin: Monitoring port %s device %s"
  391.                      " for %d minutes until %s",
  392.                      device, E_inmodem , (int) (offset / 60),
  393.                       dater( exit_time , NULL));
  394.  
  395.    interactive_processing = FALSE;
  396.  
  397.    if (!sendlist( ring,modemTimeout, offset, noconnect))
  398.                               /* Did it ring?                        */
  399.    {
  400.       interactive_processing = TRUE;
  401.       shutdown();
  402.       return CONN_INITIALIZE;     /* No --> Return to caller       */
  403.    }
  404.  
  405.    interactive_processing = TRUE;
  406.  
  407.    if(!sendlist(answer, modemTimeout,answerTimeout, noconnect))
  408.                               /* Pick up the telephone               */
  409.    {
  410.       printmsg(1,"callin: Modem failed to connect to incoming call");
  411.       shutdown();
  412.       return CONN_INITIALIZE;
  413.    }
  414.  
  415. /*--------------------------------------------------------------------*/
  416. /*           The modem is connected; now try to autobaud it           */
  417. /*--------------------------------------------------------------------*/
  418.  
  419.    printmsg(14, "callin: Modem reports connected");
  420.  
  421.  
  422.    autobaud(inspeed);         /* autobaud the modem                  */
  423.  
  424. /*--------------------------------------------------------------------*/
  425. /*        Flush the input buffer of any other input characters        */
  426. /*--------------------------------------------------------------------*/
  427.  
  428.    while (sread(&c ,1,0));    /* Discard trailing trash from modem
  429.                                  connect message                     */
  430.  
  431.    memset( &remote_stats, 0, sizeof remote_stats);
  432.                               /* Clear remote stats for login        */
  433.    time(&remote_stats.ltime); /* Remember time of last attempt conn  */
  434.    remote_stats.calls ++ ;
  435.    return CONN_LOGIN;
  436.  
  437. } /* callin */
  438.  
  439. /*--------------------------------------------------------------------*/
  440. /*    g e t m o d e m                                                 */
  441. /*                                                                    */
  442. /*    Read a modem configuration file                                 */
  443. /*--------------------------------------------------------------------*/
  444.  
  445. static boolean getmodem( const char *brand)
  446. {
  447.    char filename[FILENAME_MAX];
  448.    static char *modem = NULL;
  449.    FILE *fp;
  450.    CONFIGTABLE *tptr;
  451.    size_t subscript;
  452.    boolean success;
  453.  
  454. /*--------------------------------------------------------------------*/
  455. /*                      Validate the modem name                       */
  456. /*   Added check for validity of modem ptr -- makes NT happier - dmw  */
  457. /*--------------------------------------------------------------------*/
  458.  
  459.    if ((modem != NULL) && equal(modem, brand)) /* Already initialized?*/
  460.       return TRUE;            /* Yes --> Don't process it again      */
  461.  
  462. /*--------------------------------------------------------------------*/
  463. /*                        Initialize the table                        */
  464. /*--------------------------------------------------------------------*/
  465.  
  466.    for (tptr = modemtable; tptr->sym != nil(char); tptr++)
  467.       if (tptr->bits & (B_TOKEN | B_STRING | B_LIST | B_CLIST))
  468.          *(tptr->loc) = nil(char);
  469.  
  470.    for (subscript = 0; subscript < MODEM_LAST; subscript++)
  471.       bmodemflag[subscript] = FALSE;
  472.  
  473.    chardelay = 00;            /* Default is no delay between chars    */
  474.    dialTimeout = 40;          /* Default is 40 seconds to dial phone  */
  475.    gPacketSize = SMALL_PACKET;
  476.    vPacketSize = MAXPACK;
  477.    GPacketSize = MAXPACK;
  478.    gWindowSize = 0;
  479.    vWindowSize = 0;
  480.    GWindowSize = 0;
  481.    M_fPacketSize = MAXPACK;
  482.    M_fPacketTimeout = 20;
  483.    M_gPacketTimeout = 10;
  484.    modemTimeout  = 3;         /* Default is 3 seconds for modem cmds  */
  485.    scriptTimeout = 30;        /* Default is 30 seconds for script data*/
  486.    M_xfer_bufsize = BUFSIZ;   /* Buffering used for file transfers    */
  487.    M_MaxErr= 10;              /* Allowed errors per single packet     */
  488.  
  489. /*--------------------------------------------------------------------*/
  490. /*                 Open the modem configuration file                  */
  491. /*--------------------------------------------------------------------*/
  492.  
  493.    if (equaln(brand,"COM",3))
  494.    {
  495.       printmsg(0,"Modem type %s is invalid; Snuffles suspects \
  496. your %s file is obsolete.", brand, SYSTEMS);
  497.       panic();
  498.    }
  499.  
  500.    sprintf(filename,"%s/%s.MDM",E_confdir, brand);
  501.    if ((fp = FOPEN(filename, "r",TEXT_MODE)) == nil(FILE))
  502.    {
  503.       printmsg(0,"getmodem: Unable to locate configuration for %s",
  504.                brand);
  505.       printerr( filename );
  506.       return FALSE;
  507.    }
  508.  
  509. /*--------------------------------------------------------------------*/
  510. /*                We got the file open, now process it                */
  511. /*--------------------------------------------------------------------*/
  512.  
  513.    printmsg(3,"getmodem: loading modem configuration file %s", filename);
  514.    success = getconfig(fp, MODEM_CONFIG, B_UUCICO, modemtable, modemFlags);
  515.    fclose(fp);
  516.    if (!success)
  517.       return FALSE;
  518.  
  519. /*--------------------------------------------------------------------*/
  520. /*         Verify all required modem parameters were supplied         */
  521. /*--------------------------------------------------------------------*/
  522.  
  523.    success = TRUE;
  524.    for (tptr = modemtable; tptr->sym != nil(char); tptr++) {
  525.       if ((tptr->bits & (B_REQUIRED | B_FOUND)) == B_REQUIRED)
  526.       {
  527.          printmsg(0, "getmodem: configuration parameter \"%s\" must be set.",
  528.             tptr->sym);
  529.          success = FALSE;
  530.       } /* if */
  531.    } /* for */
  532.  
  533.    if ( success )             /* Good modem setup?                   */
  534.       modem = newstr(brand);  /* Yes --> Remember it for next time   */
  535.  
  536.    return success;
  537.  
  538. } /* getmodem */
  539.  
  540. /*--------------------------------------------------------------------*/
  541. /*    d i a l                                                         */
  542. /*                                                                    */
  543. /*    Generic modem dialer; only major limitation is that autoabaud   */
  544. /*    strings are not configurable                                    */
  545. /*--------------------------------------------------------------------*/
  546.  
  547. static boolean dial(char *number, const size_t speed)
  548. {
  549.    char buf[81];
  550.  
  551. /*--------------------------------------------------------------------*/
  552. /*                        Open the serial port                        */
  553. /*--------------------------------------------------------------------*/
  554.  
  555.    norecovery = FALSE;           // Shutdown gracefully as needed
  556.    if (openline(device, speed, bmodemflag[MODEM_DIRECT]))
  557.    {
  558.  
  559.       hostp->hstatus =  nodevice;
  560.       return FALSE;
  561.    }
  562.  
  563. /*--------------------------------------------------------------------*/
  564. /*              Flush the input buffer of any characters              */
  565. /*--------------------------------------------------------------------*/
  566.  
  567.    while (sread(buf,1,0));    /* Discard trailing trash from modem
  568.                                  connect message                     */
  569.  
  570. /*--------------------------------------------------------------------*/
  571. /*                        Initialize the modem                        */
  572. /*--------------------------------------------------------------------*/
  573.  
  574.    if (!sendlist( initialize, modemTimeout, modemTimeout, noconnect))
  575.    {
  576.       printmsg(0,"dial: Modem failed to initialize");
  577.       shutdown();
  578.       hostp->hstatus =  dial_script_failed;
  579.       return FALSE;
  580.    }
  581.  
  582. /*--------------------------------------------------------------------*/
  583. /*           Setup the dial string and then dial the modem            */
  584. /*--------------------------------------------------------------------*/
  585.  
  586.    strcpy(buf, dialPrefix);
  587.    strcat(buf, number);
  588.    if (dialSuffix != NULL)
  589.       strcat(buf, dialSuffix);
  590.  
  591.    sendstr( buf );         /* Send the command to the telephone      */
  592.  
  593.    if (!sendlist(connect,  modemTimeout, dialTimeout, noconnect))
  594.    {
  595.       hostp->hstatus =  dial_failed;
  596.       return FALSE;
  597.    }
  598.    printmsg(3, "dial: Modem reports connected");
  599.  
  600.    time( &remote_stats.lconnect );
  601.    remote_stats.calls ++ ;
  602.  
  603.    autobaud(speed);        /* Reset modem speed, if desired          */
  604.  
  605. /*--------------------------------------------------------------------*/
  606. /*                      Report success to caller                      */
  607. /*--------------------------------------------------------------------*/
  608.  
  609.    return TRUE;            /* Dial succeeded    */
  610.  
  611. } /* dial */
  612.  
  613. /*--------------------------------------------------------------------*/
  614. /*    a u t o b a u d                                                 */
  615. /*                                                                    */
  616. /*    autobaud a modem which has just connected                       */
  617. /*--------------------------------------------------------------------*/
  618.  
  619. static void autobaud( const size_t speed )
  620. {
  621.    char buf[10];
  622.  
  623.    ssleep(1);                 /*  Allow modem port to stablize       */
  624.  
  625.    if (bmodemflag[MODEM_CD])
  626.       CD();                   /* Set the carrier detect flags        */
  627.  
  628. /*--------------------------------------------------------------------*/
  629. /*                  Autobaud the modem if requested                   */
  630. /*--------------------------------------------------------------------*/
  631.  
  632.    if (!bmodemflag[MODEM_FIXEDSPEED])
  633.    {
  634.       size_t len = 0;
  635.  
  636.       memset( buf, '\0', sizeof( buf ));  /* Zero buffer                */
  637.       while ((len < sizeof buf) && sread( &buf[len],1,0))
  638.          len = strlen( buf );             /* Get speed into buffer      */
  639.  
  640.       if (len > 5)
  641.       {
  642.          char  *token;           /* Pointer to buffer value */
  643.          token = strtok(buf,WHITESPACE);
  644.          if (strlen(token))
  645.          {
  646.             size_t new_speed = (unsigned) atoi(token);
  647.             if ((new_speed != speed) && (new_speed > 300))
  648.             {
  649.                printmsg(2, "autobaud: speed select %s", token);
  650.                SIOSpeed(atoi(token));
  651.             } /* if */
  652.          } /* if */
  653.       } /* if */
  654.       else
  655.          printmsg(3, "autobaud: unable to speed select, using %d", speed);
  656.    } /* if */
  657.  
  658. } /* autobaud */
  659.  
  660. /*--------------------------------------------------------------------*/
  661. /*    s h u t d o w n                                                 */
  662. /*                                                                    */
  663. /*    Terminate modem processing via hangup                           */
  664. /*--------------------------------------------------------------------*/
  665.  
  666. void shutdown( void )
  667. {
  668.    static boolean recurse = FALSE;
  669.  
  670.    if ( ! port_active )          /* Allowed for Ctrl-Break           */
  671.       return;
  672.  
  673.    if ( !recurse )
  674.    {
  675.       boolean aborted = terminate_processing;
  676.       recurse = TRUE;
  677.       terminate_processing = FALSE;
  678.       hangup();
  679.       sendlist( dropline, modemTimeout, modemTimeout, NULL);
  680.       recurse = FALSE;
  681.       terminate_processing |= aborted;
  682.    }
  683.  
  684.    closeline();
  685.    norecovery = TRUE;
  686. }
  687.  
  688. /*--------------------------------------------------------------------*/
  689. /*    s e n d l i s t                                                 */
  690. /*                                                                    */
  691. /*    Send a NULL terminated list of send/expect strings              */
  692. /*--------------------------------------------------------------------*/
  693.  
  694. static boolean sendlist(   char **list,
  695.                            int timeout,
  696.                            int lasttimeout,
  697.                            char **failure)
  698. {
  699.    boolean expect = TRUE;
  700.  
  701.    if (list == NULL)          /* Was the field supplied?             */
  702.       return TRUE;            /* No --> Must be optional, return     */
  703.  
  704. /*--------------------------------------------------------------------*/
  705. /*     Run through the list, alternating expect and send strings      */
  706. /*--------------------------------------------------------------------*/
  707.  
  708.    while( *list != NULL)
  709.    {
  710.  
  711.       if (expect)
  712.       {
  713.          char *exp = strdup( *list );
  714.          boolean success;
  715.          checkref( exp );
  716.          success = sendalt( exp,
  717.                             (*(++list) == NULL) ? lasttimeout : timeout,
  718.                             failure);
  719.          free( exp );
  720.          if (!success)
  721.             return FALSE;
  722.       }
  723.       else
  724.          sendstr( *list++ );
  725.       expect = ! expect;
  726.    } /* while */
  727.  
  728. /*--------------------------------------------------------------------*/
  729. /*    If we made it this far, success is at hand; return to caller    */
  730. /*--------------------------------------------------------------------*/
  731.  
  732.    return TRUE;
  733. } /* sendlist */
  734.  
  735. /*--------------------------------------------------------------------*/
  736. /*    s e n d a l t                                                   */
  737. /*                                                                    */
  738. /*    Expect a string, with alternates                                */
  739. /*--------------------------------------------------------------------*/
  740.  
  741. static boolean sendalt( char *exp, int timeout, char **failure)
  742. {
  743.    int ok;
  744.  
  745.    for ( ;; )
  746.    {
  747.       char *alternate = strchr(exp, '-');
  748.  
  749.       if (alternate != nil(char))
  750.          *alternate++ = '\0';
  751.  
  752.       ok = expectstr(exp, timeout, failure);
  753.  
  754.       if ( terminate_processing )
  755.       {
  756.          shutdown();
  757.          return FALSE;
  758.       }
  759.  
  760.       if (ok || (alternate == nil(char)))
  761.          return (ok == 1);
  762.  
  763.  
  764.       if (bmodemflag[MODEM_CD] && ! CD())
  765.       {
  766.          printmsg(0,"sendalt: Serial port reports modem not ready");
  767.          return FALSE;
  768.       }
  769.  
  770.       exp = strchr(alternate, '-');
  771.       if (exp != nil(char))
  772.          *exp++ = '\0';
  773.  
  774.       printmsg(0, "sending alternate");
  775.       sendstr(alternate);
  776.    } /*for*/
  777.  
  778. } /* sendalt */
  779.  
  780. /*--------------------------------------------------------------------*/
  781. /*    s l o w w r i t e                                               */
  782. /*                                                                    */
  783. /*    Write characters to the serial port at a configurable           */
  784. /*    snail's pace.                                                   */
  785. /*--------------------------------------------------------------------*/
  786.  
  787. void slowwrite( char *s, int len)
  788. {
  789.    swrite( s , len );
  790.    if (chardelay > 0)
  791.       ddelay(chardelay);
  792. } /* slowwrite */
  793.  
  794. /*--------------------------------------------------------------------*/
  795. /*    G e t G W i n d o w                                             */
  796. /*                                                                    */
  797. /*    Report the size of the allowed window for the "g" protocol      */
  798. /*--------------------------------------------------------------------*/
  799.  
  800. INTEGER  GetGWindow(  INTEGER maxvalue , const char protocol )
  801. {
  802.    INTEGER ourWindowSize = 0;
  803.  
  804.    switch( protocol )
  805.    {
  806.       case 'g':
  807.          ourWindowSize = gWindowSize;
  808.          break;
  809.  
  810.       case 'G':
  811.          ourWindowSize = GWindowSize;
  812.          break;
  813.  
  814.       case 'v':
  815.          ourWindowSize = vWindowSize;
  816.          break;
  817.  
  818.       default:
  819.          printmsg(0,"GetGWindow: Invalid protocol %c",protocol);
  820.          panic();
  821.    }
  822.  
  823.    if ( (ourWindowSize < 1 ) || (ourWindowSize > maxvalue))
  824.       return maxvalue;
  825.    else
  826.       return ourWindowSize;
  827.  
  828. } /* GetGWindow */
  829.  
  830. /*--------------------------------------------------------------------*/
  831. /*    G e t G P a c k e t                                             */
  832. /*                                                                    */
  833. /*    Return the allowed packet size for the "g" procotol             */
  834. /*--------------------------------------------------------------------*/
  835.  
  836. INTEGER  GetGPacket( INTEGER maxvalue , const char protocol)
  837. {
  838.    INTEGER savePacketSize ;
  839.    INTEGER ourPacketSize = 0;
  840.    int bits = 6;              /* Minimum Packet Size is 64 bytes     */
  841.  
  842.    switch( protocol )
  843.    {
  844.       case 'g':
  845.          ourPacketSize = gPacketSize;
  846.          break;
  847.  
  848.       case 'G':
  849.          ourPacketSize = GPacketSize;
  850.          break;
  851.  
  852.       case 'v':
  853.          ourPacketSize = vPacketSize;
  854.          break;
  855.  
  856.       default:
  857.          printmsg(0,"GetGPacket: Invalid protocol %c",protocol);
  858.          panic();
  859.    }
  860.  
  861.    savePacketSize = ourPacketSize;
  862.  
  863. /*--------------------------------------------------------------------*/
  864. /*                 Insure the value is a power of two                 */
  865. /*--------------------------------------------------------------------*/
  866.  
  867.    while( (ourPacketSize >> (bits+1)) > 0 )
  868.       bits++;
  869.  
  870.    ourPacketSize = (ourPacketSize >> bits) << bits;
  871.    if ( savePacketSize != ourPacketSize )
  872.       printmsg(0,"packetsize for %c protocol rounded down from %d to %d",
  873.                protocol,
  874.                (int) savePacketSize, (int) ourPacketSize );
  875.  
  876. /*--------------------------------------------------------------------*/
  877. /*    Return the smaller of the argument (the largest packet size     */
  878. /*    the packet driver supports) or what the modem file allows.      */
  879. /*--------------------------------------------------------------------*/
  880.  
  881.    if ( (ourPacketSize < 1 ) || (ourPacketSize > maxvalue))
  882.       return maxvalue;
  883.    else
  884.       return ourPacketSize;
  885.  
  886. } /* GetGPacket */
  887.